package tp.pr5;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

import tp.pr5.cityLoader.CityLoaderFromTxtFile;
import tp.pr5.cityLoader.cityLoaderExceptions.WrongCityFormatException;
import tp.pr5.console.Console;
import tp.pr5.console.ConsoleController;
import tp.pr5.gui.GUIController;
import tp.pr5.gui.MainWindow;

/**
 * Aplicación que utiliza las clases de la práctica sobre el mapa
 * que aparece como ejemplo en el enunciado.
 * 
 * @author 
 * @y.exclude
 */

enum Interface {CONSOLE, SWING, BOTH};

public class Main {

	/**
	 * Creates the city, the engine and finally
	 * starts the simulation
	 * @param args
	 */
	public static void main(String[] args){
	
		String walleInterface = null;
		String map = null;
	    CommandLineParser parser = null;
	    CommandLine cmdLine = null;
	    
	    Option helpOption = new Option("h", "help",  false, "Shows this help message");
	    Option interfaceOption = new Option("i", "interface", true,  "The type of interface: console, swing or both");
	    interfaceOption.setArgName("type");
	    Option mapOption = new Option("m", "map", true, "File with the description of the city");
	    mapOption.setArgName("mapfile");
	    
		Options options = new Options();  
		options.addOption(helpOption);   
		options.addOption(interfaceOption);
		options.addOption(mapOption);
		
		try
		{
			parser  = new BasicParser();  
			cmdLine = parser.parse(options, args);
			
			if (cmdLine.hasOption("h"))
			{ 
				System.out.println("Execute this assignment with these parameters:");
				HelpFormatter formatter = new HelpFormatter();
				formatter.printHelp( Main.class.getCanonicalName(), options, true );
                System.exit(0);
            }
			
			map = cmdLine.getOptionValue("map");
            if (map == null)
            {
            	System.err.println("Map file not specified");
            	System.exit(1);
            }
            
			walleInterface = cmdLine.getOptionValue("interface");  
			if (walleInterface == null)
			{
				System.err.println("Interface not specified");
        		System.exit(1);
			}
		}
		catch(ParseException e)
		{
			System.exit(1);
		}

		if (map.indexOf(".txt") == -1)
			map += ".txt";
		File file = new File (map);
		CityLoaderFromTxtFile cityFromFile = new CityLoaderFromTxtFile();
		InputStream is = null;
		
		try {
			is = new FileInputStream(file);
		} catch (FileNotFoundException e) {
			System.err.println("Error reading the map file: " + map + " (No existe el fichero o el directorio)");
			System.exit(2);
		}
		
		try {
			City city = cityFromFile.loadCity(is);
			Place initialPlace = cityFromFile.getInitialPlace();
			Direction initialDirection = Direction.NORTH;
			RobotEngine robot= new RobotEngine(city, initialPlace, initialDirection);
			Switch(walleInterface, robot);
		}catch (WrongCityFormatException e) {
			System.err.println("Error el mapa es incorrecto");
			System.exit(2);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static void Switch(String walleInterface, RobotEngine robot) {
		
		Interface robotInterface = null;
		try{
			robotInterface = Interface.valueOf(walleInterface.toUpperCase());
		} catch(IllegalArgumentException e) {
			System.err.println("Wrong type of interface");
			System.exit(3);
		}

		switch(robotInterface)
		{
			case CONSOLE:
			{
				ConsoleController cc = new ConsoleController(robot);
				Console vc = new Console();
				cc.registerEngineObserver(vc);
				cc.registerItemContainerObserver(vc);
				cc.registerRobotObserver(vc);
				cc.startController();
				
				break;
			}
			case SWING:
			{
				GUIController gc = new GUIController(robot);
				MainWindow vg = new MainWindow(gc);
				gc.registerEngineObserver(vg);
				gc.registerItemContainerObserver(vg.getRobotPanel());
				gc.registerRobotObserver(vg.getNavigationPanel());
				gc.startController();
				
				break;
			}
			case BOTH:
			{
				ConsoleController cc = new ConsoleController(robot);
				Console vc = new Console();
				cc.registerEngineObserver(vc);
				cc.registerItemContainerObserver(vc);
				cc.registerRobotObserver(vc);
				
				GUIController gc = new GUIController(robot);
				MainWindow vg = new MainWindow(gc);
				gc.registerEngineObserver(vg);
				gc.registerItemContainerObserver(vg.getRobotPanel());
				gc.registerRobotObserver(vg.getNavigationPanel());
				gc.startController();
//				cc.startController();
				break;
			}
			default:
			{
				System.err.println("Wrong type of interface");
				System.exit(3);
			}
		}
	}
}
